//
//  CustomPalyerView.m
//  TEst
//
//  Created by xbnzd on 16/10/17.
//  Copyright © 2016年 xbnzd. All rights reserved.
//

#import "LZCustomPlayerView.h"
#import "Masonry.h"
#import "extobjc.h"
#import <AVFoundation/AVFoundation.h>

#import "LZVideoResourceLoader.h"
#import "LZVideoProgressView.h"
#import "LZVideoActivityView.h"
NSString *const kLZPlayerPauseNotification    = @"pausePlayerNotification"; //停止播放

static NSString *const LZVideoPlayerItemStatusKeyPath = @"status";//当前状态
static NSString *const LZVideoPlayerItemLoadedTimeRangesKeyPath = @"loadedTimeRanges";//加载进度
static NSString *const LZVideoPlayerItemPlaybackBufferEmptyKeyPath = @"playbackBufferEmpty";
static NSString *const LZVideoPlayerItemPlaybackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";
static NSString *const LZVideoPlayerItemPresentationSizeKeyPath = @"presentationSize";

@interface LZCustomPlayerView()<LZVideoResourceLoaderDelegate>

@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *showPlayer;
@property (nonatomic, strong) AVPlayerItem *playerItem;
@property (nonatomic, strong) NSURL  *videoURL;
@property (nonatomic, strong) NSURL  *videoURLCopy;//url备份.用来判断传进来的是否是同一个url.是的话不重新播放,继续播放
@property (nonatomic, assign) BOOL isPause; //是否暂停.默认NO
@property (nonatomic, strong) LZVideoActivityView *activityView;
@property (nonatomic, copy) void(^reloadAgainBlock)(void);
@property (nonatomic, assign) BOOL isPlayEnd;  //标记是否已经完成一遍播放.默认NO.


@property (nonatomic, strong) LZVideoResourceLoader *lzResourceLoader;
@property (nonatomic, strong) AVURLAsset *urlAsset;
@property (nonatomic, strong) LZVideoProgressView *videoProgressView;

@end

@implementation LZCustomPlayerView

//+ (instancetype)shareLZPlayer
//{
//    static LZ_CustomPlayerView *lzPlayer = nil;
//    static dispatch_once_t once;
//    dispatch_once(&once, ^{
//        lzPlayer = [[LZ_CustomPlayerView alloc] init];
//    });
//    
//    return lzPlayer;
//}

#pragma mark -
#pragma mark 生命周期
- (instancetype)init
{
    self = [super init];
    if (self) {
        
        [self initUI];
    }
    
    
    
    return self;
}

- (void)dealloc
{
    [self removeKVOAndNotification];
}

- (void)drawRect:(CGRect)rect
{
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.showPlayer.frame = self.bounds;
    [CATransaction commit];
}

#pragma mark -
#pragma mark kvo
/**
 *  @author Zhoudan, 16-10-17 15:10:06
 *
 *  添加监听
 */
- (void)addKVOAndNotification
{
    //状态监听
    [self.playerItem addObserver:self forKeyPath:LZVideoPlayerItemStatusKeyPath options:NSKeyValueObservingOptionNew context:nil];
    //缓冲进度
    [self.playerItem addObserver:self forKeyPath:LZVideoPlayerItemLoadedTimeRangesKeyPath options:NSKeyValueObservingOptionNew context:nil];
    //缓冲的一部分是否完成
    [self.playerItem addObserver:self forKeyPath:LZVideoPlayerItemPlaybackLikelyToKeepUpKeyPath options:NSKeyValueObservingOptionNew context:nil];
    //Playeritem size 渲染完成
    [self.playerItem addObserver:self forKeyPath:LZVideoPlayerItemPresentationSizeKeyPath options:NSKeyValueObservingOptionNew context:nil];
    //正在获取缓存
    [self.playerItem addObserver:self forKeyPath:LZVideoPlayerItemPlaybackBufferEmptyKeyPath options:NSKeyValueObservingOptionNew context:nil];
    
    //添加重复播放消息通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playCircleAction) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
    
    //添加停止播放通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopAction) name:kLZPlayerPauseNotification object:nil];

    
}

/**
 *  @author Zhoudan, 16-10-17 14:10:55
 *
 *  移除监听
 */
- (void)removeKVOAndNotification
{
    [self.playerItem removeObserver:self forKeyPath:LZVideoPlayerItemStatusKeyPath];
    [self.playerItem removeObserver:self forKeyPath:LZVideoPlayerItemLoadedTimeRangesKeyPath];
    [self.playerItem removeObserver:self forKeyPath:LZVideoPlayerItemPresentationSizeKeyPath];
    [self.playerItem removeObserver:self forKeyPath:LZVideoPlayerItemPlaybackBufferEmptyKeyPath];
    [self.playerItem removeObserver:self forKeyPath:LZVideoPlayerItemPlaybackLikelyToKeepUpKeyPath];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kLZPlayerPauseNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}


#pragma mark -
#pragma mark 外露方法
/**
 *  @author Zhoudan, 16-10-17 15:10:19
 *
 *  更新视频源
 *
 *  @param playURL <#playURL description#>
 */
- (void)updateURL:(NSURL *)playURL
{
    _videoURL = playURL;
}


/**
 播放视频
 */
- (void)playAction
{
    //如果正在播放,或者新传进来的地址和原有地址一样,则不处理.
    if (_isPlaying && [_videoURL.absoluteString isEqualToString:_videoURLCopy.absoluteString]) {
        return;
        
    }else{
        //重置进度条
        [self.videoProgressView resetProgress];
        
        //重置菊花
        [self.activityView resetActivity];
        
        //先删除一遍监听
        [self removeKVOAndNotification];
        
        //把播放器置为nil.停止正在播放的视频
        [self.player replaceCurrentItemWithPlayerItem:nil];

        //存储新的url,用来判断再次调用播放器是否需要重新播放
        _videoURLCopy = _videoURL;

        //标记播放的状态,用于暂停,停止
        _isPlaying = YES;
        
        NSString *str = _videoURL.absoluteString;
        if ([str hasPrefix:@"https"] ||[str hasPrefix:@"http"]) {//说明不是本地视频,需要边下边播放
            
            self.lzResourceLoader = [[LZVideoResourceLoader alloc] init];
            self.lzResourceLoader.lzResourceLoaderDelegate = self;
            //获取更改scheme后的url.加载这个url才能走自定义的resourceloader代理
            NSURL *changeSchemeURL = [self.lzResourceLoader getSchemeVideoURL:_videoURL];
            self.urlAsset = [AVURLAsset URLAssetWithURL:changeSchemeURL options:nil];
            [_urlAsset.resourceLoader setDelegate:self.lzResourceLoader queue:dispatch_get_main_queue()];
            self.playerItem = [AVPlayerItem playerItemWithAsset:self.urlAsset];
            
        }else{//是本地视频.直接播放
            self.urlAsset = [AVURLAsset URLAssetWithURL:_videoURL options:nil];
            self.playerItem = [AVPlayerItem playerItemWithAsset:self.urlAsset];
            //播放本地视频时,隐藏进度条
            [self.videoProgressView hiddenProgress];
        }
        
        //重置播放源
        [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
        
        //添加监听
        [self addKVOAndNotification];
        
    }

}

/**
 *  @author Zhoudan, 16-10-26 19:10:22
 *
 *  停止播放
 */
- (void)stopAction
{
    [self.player pause];
    _isPlaying = NO;
    [self removeKVOAndNotification];
    self.playerItem = nil;
    _videoURL = nil;
    [self.player replaceCurrentItemWithPlayerItem:nil];
}

#pragma mark -
#pragma mark  播放相关 private method
/**
 *  @author Zhoudan, 16-10-26 19:10:50
 *
 *  继续播放
 */
- (void)goOnAction
{
    if (_playCircle == NO && _isPlayEnd == YES) {
        [self.player seekToTime:CMTimeMake(0, 1)];
    }
    _isPlayEnd = NO;
    _isPause = NO;
    [self.player play];
}

/**
 *  @author Zhoudan, 16-10-17 15:10:38
 *
 *  暂停播放
 */
- (void)pauseAction
{
    _isPause = YES;
    [self.player pause];
}

/**
 *  @author Zhoudan, 16-10-27 09:10:11
 *
 *  设置循环播放
 */
- (void)playCircleAction
{
    if (_playCircle) {
        _isPlayEnd = NO;//循环播放时,不存在播放完成的概念.
        [self.player seekToTime:CMTimeMake(0, 1)];
        [self.player play];
    }else{
        _isPlayEnd = YES;
        _isPlaying = NO;
    }
    if (self.playEndBlock) {
        self.playEndBlock();
    }
}

/**
 start loading
 */
- (void)showActivityView
{
    [self.activityView startActivityForWaitSomeSecond:1.0];
}

/**
 remove loading
 */
- (void)stopActivityView
{
    [self.activityView stopActivity];
}


/**
 更新播放进度
 */
- (void)updatePlayProgress
{
    @weakify(self);
    [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 10) queue:NULL usingBlock:^(CMTime time){
        @strongify(self);
        AVPlayerItem* currentItem = self.player.currentItem;
        NSArray* loadedRanges = currentItem.seekableTimeRanges;
        if (loadedRanges.count > 0)
        {
            CMTimeRange range = [[loadedRanges objectAtIndex:0] CMTimeRangeValue];
            Float64 duration = CMTimeGetSeconds(range.start) + CMTimeGetSeconds(range.duration);

            CMTime currentTime = self.player.currentItem.currentTime;
            
            //更新播放进度条
            [self.videoProgressView setPlayProgress:CMTimeGetSeconds(currentTime)/duration];
        }
    }];

}

/**
 *  @author Zhoudan, 16-10-17 15:10:24
 *
 *  单击暂停,播放
 */
- (void)tapAction
{
    if (_isPlaying) {
        if (_isPause ) {
            [self goOnAction];
        }else{
            [self pauseAction];
        }
    }else{
        [self playAction];
    }
    
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:LZVideoPlayerItemStatusKeyPath]) {
        AVPlayerStatus statusTemp = [[change objectForKey:@"new"] intValue];
        if (statusTemp == AVPlayerStatusReadyToPlay) {
            
            [self stopActivityView];
            
            _isPlaying = YES;
            
            [self.player play];
            
            if (self.videoCanbePlayBlock) {
                self.videoCanbePlayBlock();
            }
            
            //更新播放进度条
            //            [self updatePlayProgress];
            
            
            DLog(@"________开始播放_______");
        }else if (statusTemp == AVPlayerStatusFailed){
            
            [self  stopAction];
            
            [self showActivityView];
        }
    }else if ([keyPath isEqualToString:LZVideoPlayerItemLoadedTimeRangesKeyPath]){
        //视频缓冲进度
    }else if ([LZVideoPlayerItemPresentationSizeKeyPath isEqualToString:keyPath]) {
        DLog(@"---------------------size已经渲染-------------");
        //playeritem 渲染后的原始尺寸, 如果有旋转屏幕.可在尺寸渲染出来后,添加注册通知
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
        
    }else if ([LZVideoPlayerItemPlaybackLikelyToKeepUpKeyPath isEqualToString:keyPath]){//缓冲的部分支持播放
        DLog(@"_____缓冲的部分支持播放___下载时会走多次_ 本地视频测试只走一次 ___");
        [self stopActivityView];
        
    }else if ([LZVideoPlayerItemPlaybackBufferEmptyKeyPath isEqualToString:keyPath]){//正在缓冲
        [self showActivityView];
        DLog(@"______正在缓冲_下载时可能会走多次_ 本地视频测试直走一次____");
    }
}


/**
 旋转了屏幕
 
 @param notification <#notification description#>
 */
-(void)orientationChanged:(NSNotification *)notification
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    switch (orientation) {
        case UIDeviceOrientationPortrait:
            DLog(@"~~~~~向上");
            break;
        case UIDeviceOrientationLandscapeLeft:
            DLog(@"~~~~~向左");
            break;
        case UIDeviceOrientationLandscapeRight:
            DLog(@"~~~~~向右");
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            DLog(@"~~~~~向下");
            break;
        default:
            break;
    }
    
}

#pragma mark -
#pragma mark 私有方法
- (void)initUI
{
    
    self.backgroundColor = [UIColor blackColor];
    
    [self.layer addSublayer:self.showPlayer];
    
    [self addSubview:self.videoProgressView];
    [self.videoProgressView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.mas_equalTo(0);
        make.trailing.mas_equalTo(0);
        make.bottom.mas_equalTo(0);
        make.height.mas_equalTo(1.2);
    }];
    
    [self addSubview:self.activityView];
    [self.activityView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self);
        make.size.mas_equalTo(CGSizeMake(50, 50));
    }];
    self.activityView.hidden = YES;
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
    tap.numberOfTapsRequired = 1;
    [self addGestureRecognizer:tap];
    
}

#pragma mark - resourceloader delegate
- (void)resourceLoaderDidFinishLoadingWithTask:(LZRequestVideoTask *)task
{
    DLog(@"============task load finish");
}

- (void)resourceLoaderDidFailLoadingWithTask:(LZRequestVideoTask *)task withErrorCode:(NSInteger)errorCode
{
    DLog(@"============task laod fail**");
    _isPlaying = NO;
    if (self.loadVideoFailBlock) {
        self.loadVideoFailBlock();
    }
}

- (void)resourceLoaderDidStartLoadingWithPrgoress:(CGFloat)prgoress
{
//    [self.videoProgressView setBufferProgress:prgoress];
}

#pragma mark -
#pragma mark 初始化
- (AVPlayer *)player
{
    if (!_player) {
        _player = [AVPlayer playerWithPlayerItem:self.playerItem];
    }
    
    return _player;
}

- (AVPlayerLayer *)showPlayer
{
    if (!_showPlayer) {
        _showPlayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
        _showPlayer.videoGravity = AVLayerVideoGravityResizeAspect;
        _showPlayer.backgroundColor = [UIColor clearColor].CGColor;
    }
    
    return _showPlayer;
}

- (LZVideoActivityView *)activityView
{
    if (!_activityView) {
        _activityView = [[NSBundle mainBundle] loadNibNamed:@"LZVideoActivityView" owner:self options:nil].lastObject;
    }
    
    return _activityView;
}

- (LZVideoProgressView *)videoProgressView {
    
    if (!_videoProgressView) {
        _videoProgressView = [[NSBundle mainBundle] loadNibNamed:@"LZVideoProgressView" owner:self options:nil].lastObject;
    }
    return _videoProgressView;
}

@end
